package com.xinsoft.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xinsoft.common.exception.BDException;
import com.xinsoft.entity.dto.SysDocumentNumPageParam;
import com.xinsoft.entity.po.SysDocumentNum;
import com.xinsoft.entity.vo.SysDocumentNumVo;
import com.xinsoft.mapper.SysDocumentNumMapper;
import com.xinsoft.service.SysDocumentNumService;
import lombok.Synchronized;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Objects;


/**
* @author hsm
* @description 针对表【sys_document_num(单据流水号)】的数据库操作Service实现
* @createDate 2023-06-05 16:06:51
*/
@Service
public class SysDocumentNumServiceImpl extends ServiceImpl<SysDocumentNumMapper, SysDocumentNum>
    implements SysDocumentNumService{



    @Override
    public SysDocumentNum addDocumentNum(SysDocumentNum sysDocumentNum) {
        //校验日期规则
        try {
            DateUtil.format(new Date(), sysDocumentNum.getYmdPatten());
        }catch(Exception e){
            throw new BDException("操作失败，年月日规则错误，请填写正确的规则如:yyyyMMdd !");
        }
        //校验单据id 不能重复
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("document_id",sysDocumentNum.getDocumentId());
        List list = this.list(queryWrapper);
        if(CollectionUtil.isNotEmpty(list)){
            throw new BDException("操作失败，该单据已有编号规则，请勿重复设置");
        }

        this.save(sysDocumentNum);
        return sysDocumentNum;
    }

    @Override
    public SysDocumentNum editDocumentNum(SysDocumentNum sysDocumentNum) {
        //保存编号设置
        //校验日期规则
        try {
            DateUtil.format(new Date(), sysDocumentNum.getYmdPatten());
        }catch(Exception e){
            throw new BDException("操作失败，年月日规则错误，请填写正确的规则如:yyyyMMdd");
        }
        //校验单据id 不能重复
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("document_id",sysDocumentNum.getDocumentId());
        queryWrapper.ne("id",sysDocumentNum.getId());
        List list = this.list(queryWrapper);
        if(CollectionUtil.isNotEmpty(list)){
            throw new BDException("操作失败，该单据已有编号规则，请勿重复设置");
        }
        this.updateById(sysDocumentNum);
        return sysDocumentNum;
    }

    @Override
    public IPage<SysDocumentNumVo> findPageListByParam(SysDocumentNumPageParam param) {

        //分页
        Page<SysDocumentNumVo> page = new Page<SysDocumentNumVo>(param.getCurrentPage(), param.getPageSize());
        //查询分页
        IPage<SysDocumentNumVo> pageList = this.baseMapper.findListByParam(page, param.getDocumentId());
        //返回值
        return pageList;
    }

    @Override
    public List<SysDocumentNumVo> findListByParam(SysDocumentNumPageParam param) {
        //查询分页
        List<SysDocumentNumVo> list = this.baseMapper.findListByParam( param.getDocumentId());
        //返回值
        return list;
    }


    @Override
    public void del(List<Integer> ids) {
        // 判段是否启用
        QueryWrapper<SysDocumentNum> query = new QueryWrapper<>();
        query.eq("set_status",1);//启用
        query.in("id",ids);
        List<SysDocumentNum> sets = this.list(query);
        //判断是否已启用
        if(CollectionUtil.isNotEmpty(sets)){
            throw new BDException("操作失败，"+sets.get(0).getPrefix()+"已启用无法删除！");
        }
        // 删除
        removeByIds(ids);
    }

    @Override
    public void enable(List<Integer> ids) {
        UpdateWrapper<SysDocumentNum> sysDocumentNumUpdateWrapper = new UpdateWrapper<>();
        sysDocumentNumUpdateWrapper.set("set_status",1);//启用
        sysDocumentNumUpdateWrapper.in("id",ids);
        this.update(sysDocumentNumUpdateWrapper);
    }

    @Override
    public void disable(List<Integer> ids) {
        UpdateWrapper<SysDocumentNum> sysDocumentNumUpdateWrapper = new UpdateWrapper<>();
        sysDocumentNumUpdateWrapper.set("set_status",0);//禁用
        sysDocumentNumUpdateWrapper.in("id",ids);
        this.update(sysDocumentNumUpdateWrapper);
    }

    @Override
    public SysDocumentNum getSysDocumentNum(Integer id) {
        SysDocumentNum entity =  this.getById(id);
        return entity;
    }

    @Override
    @Synchronized
    public void incrementLastSerialByDocumentId(Integer documentId){
        UpdateWrapper updateWrapper  = new UpdateWrapper();
        updateWrapper.setSql("last_serial = last_serial+1,update_time = now()");
        updateWrapper.eq("document_id",documentId);
        updateWrapper.isNotNull("last_serial");
        boolean r = update(updateWrapper);
        if (!r){
            throw  new BDException("操作失败，编号设置异常，请联系管理员！");
        }

    }

    @Override
    public String getSysDocumentNumByDocumentId(Integer documentId){


        //说明：根据单据id 和对应的设置生成一条编号，并将顺序号重置加一。
        // 根据编号id查询出对应的设置
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("document_id",documentId);
        SysDocumentNum sysDocumentNum = this.getOne(queryWrapper);
        if(sysDocumentNum==null){
            throw new BDException("编号获取失败，该单据编号未设置编号规则，请先设置！");
        }
        if(!Objects.equals(sysDocumentNum.getSetStatus(),1)){
            throw new BDException("编号获取失败，该单据编号设置未启用！");
        }
        if(StringUtils.isEmpty(sysDocumentNum.getSerialPatten())){
            throw new BDException("编号获取失败,规则不能为空！");
        }

        String code = generatorCode(sysDocumentNum);

        return code;
    }


    /**
     * 获取下一个顺序号
     * @param sysDocumentNum
     * @return
     */
    private Integer getNextSerial(SysDocumentNum sysDocumentNum){
        //顺序号默认从一开始
        int result = -2;

        // 没有开始的直接返回-2
        if(sysDocumentNum.getLastSerial()==null){
            return result;
        }
        Date now = new Date();
        Date lastUpdate = sysDocumentNum.getUpdateTime()==null?sysDocumentNum.getCreateTime():sysDocumentNum.getUpdateTime();
        int nowNum = DateUtil.year(now);
        int lastUpdateNum = DateUtil.year(lastUpdate);
        //不是同一年则顺序号直接返回-2
        if(nowNum!=lastUpdateNum){
            return result;
        }

        //根据周期 计算下一个顺序号
        //周期 1-日 2-周 3-月 4-季度 5-年
        switch (sysDocumentNum.getNumPeriod()) {
            case 1:
                nowNum =DateUtil.dayOfYear(now);
                lastUpdateNum = DateUtil.dayOfYear(lastUpdate);
                break;
            case 2:
                nowNum =DateUtil.weekOfYear(now);
                lastUpdateNum = DateUtil.weekOfYear(lastUpdate);
                break;
            case 3:
                nowNum =DateUtil.month(now);
                lastUpdateNum = DateUtil.month(lastUpdate);
                break;
            case 4:
                nowNum =DateUtil.quarter(now);
                lastUpdateNum = DateUtil.quarter(lastUpdate);
                break;
            default:
                break;
        }

        //不处于同一区间内也直接返回-2
        if(nowNum!=lastUpdateNum){
            return result;
        }
        //处于同一区间内加一取下一个
        result = sysDocumentNum.getLastSerial()+1;
        return result;
    }

    @Synchronized
    private String generatorCode(SysDocumentNum sysDocumentNum){
        // 获取下一个顺序号
        int nextSerial =  getNextSerial(sysDocumentNum);

        if(nextSerial<0){
            //顺序号小于0，定义为下一周期开始，更新lastSerial为0
            sysDocumentNum.setLastSerial(0);
            sysDocumentNum.setUpdateTime(null);
            this.updateById(sysDocumentNum);
            nextSerial = 1;
        }

        String code = "";
        // 解析编号规则
        String[] patten =  sysDocumentNum.getSerialPatten().split("[+]");
        for (String s : patten) {
            if(s.contains("前缀")){
                code += sysDocumentNum.getPrefix();
            }else if(s.contains("年月日规则")){
                code += DateUtil.format(new Date(),sysDocumentNum.getYmdPatten());
            }else if(s.contains("顺序号")){
                code += String.format("%0"+sysDocumentNum.getSerialNum()+"d",nextSerial);
            }else {
                code += (s.replaceAll("\"","").replaceAll("'",""));
            }
        }
        return code;
    }

    /**
     * 生成派工单编码
     * @param sysDocumentNum
     * @return
     */
    @Synchronized
    public String generatorDispatchCodeCode(SysDocumentNum sysDocumentNum){
        // 获取下一个顺序号
        int nextSerial =  getNextSerial(sysDocumentNum);

        if(nextSerial<0){
            //顺序号小于0，定义为下一周期开始，更新lastSerial为0
            sysDocumentNum.setLastSerial(0);
            sysDocumentNum.setUpdateTime(null);
            this.updateById(sysDocumentNum);
            nextSerial = 1;
        }

        String code = "";
        // 解析编号规则
        String[] patten =  sysDocumentNum.getSerialPatten().split("[+]");
        for (String s : patten) {
            if(s.contains("前缀")){
                code += sysDocumentNum.getPrefix();
            }else if(s.contains("年月日规则")){
                code += DateUtil.format(new Date(),sysDocumentNum.getYmdPatten());
            }else if(s.contains("顺序号")){
                code += String.format("%0"+sysDocumentNum.getSerialNum()+"d",nextSerial);
            }else {
                code += (s.replaceAll("\"","").replaceAll("'",""));
            }
        }
        return code;
    }
}




